package Algorithms;

import General.AdjacencyMatrix;
import General.DistanceMatrix;
import General.MembershipMatrix;

public abstract class ClusteringAlgorithm {
	protected double m;
	protected double eps;
	protected AdjacencyMatrix a;
	protected int c;
	protected int[] centers;
	protected DistanceMatrix d;
	public MembershipMatrix u;
	protected int n;
	
	public abstract MembershipMatrix run();
	
	public ClusteringAlgorithm(AdjacencyMatrix a, DistanceMatrix d, double m, double eps, int[] centers){
		this.m=m;
		this.eps=eps;
		this.a=a;
		this.d=d;
		this.centers=centers;
		c=centers.length;
		n=a.getSize();
		
		u=new MembershipMatrix(n, c);
	}
	
	public double membershipDegree(int i, int k)
	{ // checked!
		double s=0;
		for (int j=0; j<c; j++)
			if (d.get(i, centers[k])==0 && d.get(i, centers[j])==0) // define 0/0 as 1
				s++;
			else
				s+=Math.pow((d.get(i, centers[k])/d.get(i, centers[j])), 2/(m-1));
		
		return 1/s;
	}
	
	public double fillMembershipMatrix()
	// checked!
	{ // fill matrix U, and returns the maximal change;
		double max_change=0, temp;
		for (int i=0; i<n; i++)
			for (int k=0; k<c; k++)
			{
				temp=membershipDegree(i, k);
				if (Math.abs(temp - u.get(i, k))>max_change)
					max_change=Math.abs(temp - u.get(i, k));
				u.set(i, k, temp);
			}
		return max_change;
	}
	
	public double[] vectorMul (double a, byte[] v) // calculates a multipication of vector and double
	{
		double[] res= new double[v.length];
		for (int i=0; i<v.length; i++)
		{
			res[i]=a*v[i];
		}
		return res;
			
	}
	
	public void vectorSum (double[] v1, double[] v2) // calculates the sum of 2 vectors
	{
		//double[] res= new double[v1.length];
		for (int i=0; i<v1.length; i++)
		{
			v1[i]=v1[i]+v2[i];
		}
		//return res;
	}
	
	public int closestNode (double[] center)   // returns the number of node that it's vector is the closest to the given vector
	{
		int min=-1;
		double min_sum=n;
		for (int i=0; i<n; i++)
		{
			byte[] vec = a.getVector(i);
			double sum=0;
			
			for (int j=0; j<n; j++)
				sum+=Math.abs((double)(vec[j])-center[j]);
			
			if (sum<min_sum) 
				{
				min_sum=sum;
				min=i;
				}
		}
		
		return min;
	}
	

}
